﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

namespace nPress.Core.Interfaces
{
    public interface IRepository : IDisposable
    {
     
        #region Save / Update

        /// <summary>
        /// Saves or updates the given entity in the data store.
        /// </summary>
        /// <param name="entity">The entity to save or update.</param>
        /// <remarks>The entity is not actually saved or updated until the transaction is committed.</remarks>
        void SaveOrUpdate(object entity);

        /// <summary>
        /// Saves the given entity in the data store.
        /// </summary>
        /// <param name="entity">The entity to save.</param>
        /// /// <remarks>The entity is not actually saved until the transaction is committed.</remarks>
        void Save(object entity);

        /// <summary>
        /// Updates the given entity in the data store.
        /// </summary>
        /// <param name="entity">The entity to update.</param>
        /// /// <remarks>The entity is not actually updated until the transaction is committed.</remarks>
        void Update(object entity);

        /// <summary>
        /// Create the relationship between the entity and its child
        /// </summary>
        /// <param name="entity">The entity to update.</param>
        /// <param name="child">The entity to add</param>
        /// <param name="propertyName">Property name for the child</param>
        void CreateRelationShip(Object entity, Object child, string propertyName);

        /// <summary>
        /// remove the relationship between the entity and its child
        /// </summary>
        /// <param name="entity">The entity to update.</param>
        /// <param name="child">The entity to remove</param>
        /// <param name="propertyName">Property name for the child</param>
        void RemoveRelationShip(Object entity, Object child, string propertyName);
        #endregion

        #region Find

        /// <summary>
        /// Retrieves an entity from the data store.
        /// </summary>
        /// <typeparam name="T">The type of entity to retrieve.</typeparam>
        /// <param name="id">The ID of the entity.</param>
        /// <returns>An entity of type T.</returns>
        T FindOne<T>(object id) where T : class;

        /// <summary>
        /// Retrieves an entity from the data store.
        /// </summary>
        /// <typeparam name="T">The type of entity to retrieve.</typeparam>
        /// <param name="expression">Expression Linq</param>
        /// <returns>An entity of type T.</returns>
        T FindOne<T>(Expression<Func<T, bool>> expression) where T : class;

        /// <summary>
        /// Retrieves an entity from the data store.
        /// </summary>
        /// <typeparam name="T">The type of entity to retrieve.</typeparam>
        /// <param name="id">The ID of the entity.</param>
        /// <param name="entity">An entity of type T.</param>
        /// <returns>True id entity exists</returns>
        bool TryFindOne<T>(object id, out T entity) where T : class;

        /// <summary>
        /// Retrieves an entity from the data store.
        /// </summary>
        /// <typeparam name="T">The type of entity to retrieve.</typeparam>
        /// <param name="expression">Expression Linq</param>
        /// <param name="entity">An entity of type T.</param>
        /// <returns>True id entity exists</returns>
        bool TryFindOne<T>(Expression<Func<T, bool>> expression, out T entity) where T : class;

        /// <summary>
        /// Retrieves a collection of entities
        /// </summary>
        /// <typeparam name="T">The type of entity to retrieve.</typeparam>
        /// <returns>List of entities of type T</returns>
        IList<T> FindAll<T>() where T : class;

        /// <summary>
        /// Retrieves a collection of entities
        /// </summary>
        /// <typeparam name="T">The type of entity to retrieve.</typeparam>
        /// <param name="expression">Linq expression</param>
        /// <returns>List of entities of type T</returns>
        IList<T> FindAll<T>(Expression<Func<T, bool>> expression) where T : class;

        /// <summary>
        /// Retrieves a collection of entities
        /// </summary>
        /// <typeparam name="T">The type of entity to retrieve.</typeparam>
        /// <param name="ids">Array of id</param>
        /// <returns>List of entities of type T</returns>
        IList<T> FindAll<T>(object[] ids) where T : class;

        /// <summary>
        /// Create a queryable object (Linq) of entities
        /// </summary>
        /// <typeparam name="T">The type of entity to retrieve.</typeparam>
        /// <returns>Queryable object</returns>
        IQueryable<T> Find<T>() where T : class;

        /// <summary>
        /// Create a queryable object (Linq) of entities
        /// </summary>
        /// <typeparam name="T">The type of entity to retrieve.</typeparam>
        /// <param name="expression">Linq expression</param>
        /// <returns>Queryable object</returns>
        IQueryable<T> Find<T>(Expression<Func<T, bool>> expression) where T : class;

        #endregion

        #region Delete

        /// <summary>
        /// Deletes an entity from the data store.
        /// </summary>
        /// <param name="entity">The entity to delete.</param>
        void Delete(object entity);

        #endregion

        #region Count

        /// <summary>
        /// Get the number of entities 
        /// </summary>
        /// <typeparam name="T">The type of entity</typeparam>
        /// <returns></returns>
        int Count<T>() where T : class;

        /// <summary>
        /// Get the number of entities 
        /// </summary>
        /// <typeparam name="T">The type of entity</typeparam>
        /// <param name="expression">Linq expression</param>
        /// <returns></returns>
        int Count<T>(Expression<Func<T, bool>> expression) where T : class;

        #endregion

        #region Transaction

        /// <summary>
        /// Begins an NHibernate transaction.
        /// </summary>
        void BeginTransaction();

        /// <summary>
        /// Commits an NHibernate transaction.
        /// </summary>
        void CommitTransaction();

        /// <summary>
        /// Rolls back an NHibernate transaction.
        /// </summary>
        void RollbackTransaction();

        #endregion

        #region Other

       /// <summary>
        /// Opens the gateway to the data store.
        /// </summary>
        /// <returns>True if gateway was already open.</returns>
        /// <remarks>Gateway is open when session is open and connection is open.</remarks>
        bool Open();

        /// <summary>
        /// Closes the gateway to the data store.
        /// </summary>
        /// <remarks>This method disconnects the session and closes it.</remarks>
        void Close();

        /// <summary>
        /// Disposes of this instance of the Repository class.
        /// </summary>
        /// <param name="isDisposing">Flag that tells the .NET runtime if this class is disposing.</param>
        /// <remarks>This method kills the existing NHibernate session, transaction, and interceptor.</remarks>
        void Dispose(bool isDisposing);

        /// <summary>
        /// Clear all cache in context
        /// </summary>
        void ClearContext();

        /// <summary>
        /// Detach entity from its context (DynamicProxy) 
        /// </summary>
        /// <typeparam name="T">The type of entity</typeparam>
        /// <param name="entity">Entity to detach</param>
        /// <returns>Clean entity</returns>
        T Detach<T>(T entity) where T : class;

        /// <summary>
        /// Initialize the schema in datasource
        /// </summary>
        void InitializeRepository();

        #endregion

    }
}
